package com.xzj.getway.filter;

import cn.hutool.core.util.IdUtil;
import com.xzj.common.core.constants.LogConstants;
import com.xzj.getway.constants.GatewayConstants;
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.util.Strings;
import org.slf4j.MDC;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.HttpMethod;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.net.InetSocketAddress;
import java.util.concurrent.atomic.AtomicReference;

/**
 * @program: xzj-admin
 * @ClassName: GatewayFilter
 * @description: 网关过滤器
 * @author: XiaZunJun
 * @create: 2024-08-06 14:58
 */
@Component
@Slf4j
public class GatewayFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //1.用户发送请求到api网关
        log.info("进入网关过滤器");
        //2.获取用户请求的request
        ServerHttpRequest request = exchange.getRequest();
        String schema = request.getURI().getScheme();
        if("http".equals(schema) || "https".equals(schema)){
            HttpMethod method = request.getMethod();
            //3.配置请求日志
            log.info("请求唯一标识:{}",request.getId());
            log.info("请求路径：{}",request.getPath().value());
            log.info("请求方法：{}",method);
            InetSocketAddress address = request.getRemoteAddress();
            log.info("请求来源地址：{} - {}",address,address.getHostName());
            String requestParams = "{}";
            if(HttpMethod.POST.equals(method)){
                //获取request body
                Flux<DataBuffer> cachedBody = exchange.getAttribute(GatewayConstants.CACHE_REQUEST_BODY_OBJECT_KEY);
                if(cachedBody!=null){
                    requestParams = toRaw(cachedBody);
                }
            }else{
                requestParams = request.getQueryParams().toString();
            }
            log.info("请求参数：{}",requestParams);
        }
        return returnMono(request,exchange,chain);
    }

    private Mono<Void> returnMono(ServerHttpRequest request,ServerWebExchange exchange, GatewayFilterChain chain){
        //4.传递traceId
        String traceId = IdUtil.fastSimpleUUID();
        if(request.getHeaders().get(LogConstants.TRACE_ID)!= null){
            traceId = request.getHeaders().get(LogConstants.TRACE_ID).get(0);
        }else{
            request.mutate().header(LogConstants.TRACE_ID, traceId).build();
        }
        MDC.put(LogConstants.TRACE_ID, traceId);
        //把新的 exchange放回到过滤链
        return chain.filter(exchange.mutate().request(request).build());
    }

    @Override
    public int getOrder() {
        // 确保此过滤器在其他过滤器之后运行
        return Ordered.HIGHEST_PRECEDENCE+1;
    }

    /**
     * 用于获取请求参数
     *
     * @param body
     * @return
     */
    private static String toRaw(Flux<DataBuffer> body) {
        AtomicReference<String> rawRef = new AtomicReference<>();
        body.subscribe(buffer -> {
            byte[] bytes = new byte[buffer.readableByteCount()];
            buffer.read(bytes);
            DataBufferUtils.release(buffer);
            rawRef.set(Strings.fromUTF8ByteArray(bytes));
        });
        return rawRef.get();
    }

}
